/**
 * The contents of this file are subject to the license and copyright detailed in the LICENSE and NOTICE files at the root of the source tree and available online at
 * http://www.askosi.org/license.html
 */
package be.destin.skos.search;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import be.destin.skos.core.Concept;
import be.destin.skos.core.ConceptScheme;
import be.destin.skos.core.NoScheme;
import be.destin.skos.core.Profile;
import be.destin.skos.core.SchemeInterface;
import be.destin.skos.core.SkosManager;
import be.destin.skos.html.SkosHtmlManager;

public class SkosSearch {

	private static final Logger log = Logger.getLogger(SkosSearch.class);

	public static ArrayList<SearchResult> analyzeSentence (SkosHtmlManager skosHtmlManager, boolean strictLanguage, List<SchemeInterface> schemes, String sentence) {
		if (skosHtmlManager == null) return null;
		if (sentence == null) return null;
		ArrayList<SchemeInterface> listOfAuthorityLists = new ArrayList<SchemeInterface>();
		if (schemes != null && !schemes.isEmpty()) {
			for (SchemeInterface aScheme : schemes) {
				if ( (aScheme != null)
						&& (aScheme.getClass() != NoScheme.class) ) {
					listOfAuthorityLists.add(aScheme);
				}
			}
		} else {
			for (SchemeInterface aScheme: skosHtmlManager.getSkosManager().getConceptSchemes()) {
				if ( (aScheme.getClass() == ConceptScheme.class)
						&& (((ConceptScheme)aScheme).getMaxDepth() > 1) ) {
					listOfAuthorityLists.add(aScheme);
				}
			}
		}

		if (listOfAuthorityLists.size() <= 0) {
			log.error("No available Schemes within " + skosHtmlManager.getSkosManager().getConfigDirectory());
			return null;
		}

		ArrayList<SearchResult> result = new ArrayList<SearchResult>();
		for (SchemeInterface theAuthorityList : listOfAuthorityLists) {
			log.debug("Scheme "+theAuthorityList.getAbout()+"="+theAuthorityList.getClass().getName());
			Collection<SearchResult> tri = theAuthorityList.labelMatch(sentence,skosHtmlManager.getLanguage(), strictLanguage, LabelMatchType.SINGULAR_SENTENCES);
			log.debug(tri.size()+" concepts: "+tri);
			if (tri.size() <= 0) continue;
			
			result.addAll(tri);
		}
		return result;
	}

	public static ArrayList<Concept> searchSentence (SkosHtmlManager skosHtmlManager, boolean strictLanguage, SchemeInterface singleScheme, String sentence) {
		SchemeInterface[] someSchemes = new SchemeInterface[0];
		if (singleScheme != null) {
		  someSchemes = new SchemeInterface[1];
		  someSchemes[0] = singleScheme;
		}
		return search (skosHtmlManager, strictLanguage, someSchemes, sentence, LabelMatchType.SINGULAR_SENTENCES, null);
	}

	public static ArrayList<Concept> search (SkosHtmlManager skosHtmlManager, boolean strictLanguage, SchemeInterface singleScheme, String query, boolean startsWith, boolean byPieces, Collection<Concept> filter) {
		LabelMatchType matchType = LabelMatchType.STARTS_WITH;
		if (!startsWith) {
			matchType = LabelMatchType.ANYWHERE;
		}
		if (byPieces) {
			matchType = LabelMatchType.INDEPENDANT_PIECES;
		}
		SchemeInterface[] someSchemes = new SchemeInterface[0];
		if (singleScheme != null) {
		  someSchemes = new SchemeInterface[1];
		  someSchemes[0] = singleScheme;
		} else {
			Profile aProfile = skosHtmlManager.getProfileData();
			if (aProfile != null) {
				SkosManager skosManager = skosHtmlManager.getSkosManager();
				List<String> profileSchemes = aProfile.getBrowsedList();
				LinkedList<SchemeInterface> schemeList = new LinkedList<SchemeInterface>();
				for (String schemeCode : profileSchemes) {
					   if (schemeCode.isEmpty()) continue;
				       SchemeInterface aScheme = skosManager.getScheme(schemeCode);
				       if (aScheme != null) {
				    	   schemeList.add(aScheme);
				       }					
				}
				someSchemes = schemeList.toArray(someSchemes);
			}
		}
		return search (skosHtmlManager, strictLanguage, someSchemes, query, matchType, filter);
	}

	public static ArrayList<Concept> search (SkosHtmlManager skosHtmlManager, boolean strictLanguage, SchemeInterface[] someSchemes, String query, LabelMatchType matchType, Collection<Concept> filter) {
			
		ArrayList<SearchResult>searchResult = searchWithResults(skosHtmlManager,strictLanguage,someSchemes,query, matchType, filter);
		if (searchResult == null) return null;
		return skosHtmlManager.getSkosManager().getMatchingConcepts(searchResult);
	}

	public static ArrayList<SearchResult> searchWithResults (SkosHtmlManager skosHtmlManager, boolean strictLanguage, SchemeInterface[] someSchemes, String query, LabelMatchType matchType, Collection<Concept> filter) {
		
		if (skosHtmlManager == null) return null;
		if (query == null) return null;
		log.debug("current="+query);

		ArrayList<SchemeInterface> listOfAuthorityLists = new ArrayList<SchemeInterface>();
		if (someSchemes != null && (someSchemes.length > 0)) {
			for (SchemeInterface aScheme : someSchemes) {
				if ( (aScheme != null) && (aScheme.getClass() != NoScheme.class) ) {
					listOfAuthorityLists.add(aScheme);
				}
			}
		} else {
			LinkedList<String> wantedSchemes = skosHtmlManager.getProfileData().getBrowsedList();
			if (wantedSchemes != null) {
				for (String aboutScheme: wantedSchemes) {
					SchemeInterface aScheme = skosHtmlManager.getSkosManager().getConceptScheme(aboutScheme);
					if (aScheme != null) {
						listOfAuthorityLists.add(aScheme);
					}
				}				
			}
			if (listOfAuthorityLists.isEmpty()) {
				for (SchemeInterface aScheme: skosHtmlManager.getSkosManager().getConceptSchemes()) {
					listOfAuthorityLists.add(aScheme);
				}
			}
		}

		if (listOfAuthorityLists.isEmpty()) {
			log.error("No available Schemes within " + skosHtmlManager.getSkosManager().getConfigDirectory());
			return null;
		}

		ArrayList<SearchResult> result = new ArrayList<SearchResult>();
		String toStore="";
		int i=0;
		for (SchemeInterface theAuthorityList : listOfAuthorityLists) {
			log.debug("Scheme "+theAuthorityList.getAbout()+"="+theAuthorityList.getClass().getName());
			ArrayList<SearchResult> tri = theAuthorityList.labelMatch(query,skosHtmlManager.getLanguage(), strictLanguage, matchType, filter);
			log.debug(tri.size()+" concepts: "+tri);
			if (tri.size() <= 0) continue;
			i += tri.size();
			result.addAll(tri);
		}
		log.debug(i+" concepts for "+query+", stored as:"+toStore);
		return result;
	}
}
